//+------------------------------------------------------------------+
//|                                                  SignalFrAMA.mqh |
//|                             Copyright 2000-2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Expert/ExpertSignal.h>    // 专家顾问信号基类（提供信号生成框架）

// wizard description start（MQL5 策略向导描述，用于识别类信息与参数）
//+------------------------------------------------------------------+
//| 类功能描述                                                       |
//| Title=基于分形自适应移动平均线（Fractal Adaptive Moving Average）的交易信号 |
//| Type=SignalAdvanced                                              |
//| Name=Fractal Adaptive Moving Average                             |
//| ShortName=FraMA                                                  |
//| Class=CSignalFrAMA                                               |
//| Page=signal_frama                                                |
//| Parameter=PeriodMA,int,12,平均周期（FrAMA 计算周期）               |
//| Parameter=Shift,int,0,时间偏移（指标位移，0=无偏移）               |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,应用价格（计算FrAMA的基础价格）|
//+------------------------------------------------------------------+
// wizard description end

//+------------------------------------------------------------------+
//| CSignalFrAMA 类：基于分形自适应移动平均线（FrAMA）的交易信号生成器   |
//| 核心能力：继承自 CExpertSignal，通过调用 FrAMA 指标（根据市场分形特性动态调整平滑系数的均线）， |
//|           识别4类多空信号（价格位置、反向交叉、同向交叉、穿刺形态），   |
//|           支持通过“信号权重”调整不同形态的优先级，适配不同波动特性的市场   |
//| 核心逻辑：FrAMA 结合市场分形维度（反映价格波动复杂度）动态调整平滑参数，  |
//|           高波动时降低平滑度（快速响应），低波动时提高平滑度（过滤噪音）； |
//|           通过“价格与FrAMA的位置关系”“交叉方向”“穿刺形态”判断信号，兼顾灵敏与稳定 |
//| 适用场景：全市场环境（趋势/震荡均可），尤其适合价格波动特性多变的品种（如加密货币、小盘股）， |
//|           可单独作为趋势指标或与波动率指标配合使用                   |
//+------------------------------------------------------------------+
class CSignalFrAMA : public CExpertSignal
  {
protected:
   // 核心组件与参数（保护，子类可访问）
   CiFrAMA           m_ma;             // FrAMA 指标对象（封装分形自适应均线的计算与数据读取）
   // FrAMA 指标可调参数（与指标原生参数对应，默认配置平衡灵敏度与稳定性）
   int               m_ma_period;      // 平均周期（FrAMA 核心周期，默认12，值越大基础平滑度越高）
   int               m_ma_shift;       // 时间偏移（指标在图表上的位移，0=无偏移，正数=右移，负数=左移）
   ENUM_APPLIED_PRICE m_ma_applied;    // 应用价格（计算FrAMA的基础价格，默认PRICE_CLOSE，即收盘价）
   // 市场形态信号权重（0-100，值越大信号优先级越高，默认配置突出反转交叉信号）
   int               m_pattern_0;      // 形态0权重：价格在指标的预期侧（如多单需价格在FrAMA上方）
   int               m_pattern_1;      // 形态1权重：价格与指标反向交叉（如价格从上方下穿FrAMA后反弹→空单）
   int               m_pattern_2;      // 形态2权重：价格与指标同向交叉（如价格从下方上穿FrAMA后延续→多单）
   int               m_pattern_3;      // 形态3权重：穿刺形态（价格短暂刺穿FrAMA后回归，确认趋势延续）

public:
   //----------------------------------------------------------------
   // 构造与析构函数
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化 FrAMA 信号生成器
    * @details 1. 初始化 FrAMA 指标对象及默认参数（周期=12，偏移=0，应用价格=收盘价）；
    *          2. 设置默认信号权重（形态0=90，形态1=100，形态2=80，形态3=60）；
    *          3. 启用全价格序列（开盘价+最高价+最低价+收盘价），因信号判断需多价格维度数据；
    *          4. 继承父类 CExpertSignal 的信号框架初始化
    */
                     CSignalFrAMA(void);

   /**
    * @brief 析构函数：清理 FrAMA 信号生成器资源
    * @details 释放指标对象占用的内存，依赖父类析构逻辑完成信号框架资源清理
    */
                    ~CSignalFrAMA(void);

   //----------------------------------------------------------------
   // FrAMA 指标参数配置：修改核心指标参数（外部调用接口）
   //----------------------------------------------------------------
   /**
    * @brief 设置 FrAMA 平均周期（核心参数）
    * @param value [in] 周期值（需>0，建议10-30，值越大对极端波动的容忍度越高）
    */
   void              PeriodMA(int value);

   /**
    * @brief 设置 FrAMA 时间偏移（图表显示调整）
    * @param value [in] 偏移值（整数，0=无偏移，正数=指标右移，负数=指标左移，不影响计算逻辑）
    */
   void              Shift(int value);

   /**
    * @brief 设置 FrAMA 应用价格（计算基础）
    * @param value [in] 价格类型（ENUM_APPLIED_PRICE 枚举，如 PRICE_CLOSE=收盘价，PRICE_HIGH=最高价）
    */
   void              Applied(ENUM_APPLIED_PRICE value);

   //----------------------------------------------------------------
   // 信号权重配置：修改不同市场形态的信号强度（外部调用接口）
   //----------------------------------------------------------------
   /**
    * @brief 设置形态0（价格位置）的信号权重
    * @param value [in] 权重值（0-100，建议80-100，值越大越重视价格与FrAMA的基础位置关系）
    */
   void              Pattern_0(int value);

   /**
    * @brief 设置形态1（反向交叉）的信号权重
    * @param value [in] 权重值（0-100，建议90-100，值越大越重视趋势可能反转的交叉信号）
    */
   void              Pattern_1(int value);

   /**
    * @brief 设置形态2（同向交叉）的信号权重
    * @param value [in] 权重值（0-100，建议70-90，值越大越重视趋势延续的交叉信号）
    */
   void              Pattern_2(int value);

   /**
    * @brief 设置形态3（穿刺形态）的信号权重
    * @param value [in] 权重值（0-100，建议50-70，值越大越重视趋势中的短暂回调后延续信号）
    */
   void              Pattern_3(int value);

   //----------------------------------------------------------------
   // 参数验证：确保指标参数与信号配置有效（信号生成前提）
   //----------------------------------------------------------------
   /**
    * @brief 验证 FrAMA 指标参数与信号配置的有效性
    * @return bool - 验证结果：true=所有参数有效，false=存在无效参数（如周期≤0）
    * @note 验证逻辑：
    *       1. 先调用父类 ValidationSettings() 验证信号框架基础参数（如品种、周期）；
    *       2. 额外验证 FrAMA 平均周期（m_ma_period）是否>0，若无效则输出错误日志并返回false；
    *       3. 偏移量（m_ma_shift）和应用价格（m_ma_applied）无范围限制，无需额外验证
    */
   virtual bool      ValidationSettings(void);

   //----------------------------------------------------------------
   // 指标初始化：创建并注册 FrAMA 指标（信号生成的前提）
   //----------------------------------------------------------------
   /**
    * @brief 初始化 FrAMA 指标及信号所需的价格序列数据
    * @param indicators [in] 指标集合对象（用于管理所有策略用到的指标，如 FrAMA、波动率等）
    * @return bool - 初始化结果：true=成功（指标创建+注册到指标集合），false=失败
    * @note 调用流程：
    *       1. 先调用父类 InitIndicators() 完成基础信号框架与价格序列初始化；
    *       2. 调用内部 InitMA() 方法创建 FrAMA 指标，绑定当前品种、周期及指标参数（周期、偏移、应用价格）；
    *       3. 若指标创建失败（如参数无效、品种不支持），返回 false 并终止信号生成
    */
   virtual bool      InitIndicators(CIndicators *indicators);

   //----------------------------------------------------------------
   // 信号判断核心方法：生成多空信号权重（策略决策依据）
   //----------------------------------------------------------------
   /**
    * @brief 判断当前市场是否满足多单（买入）开仓条件，返回信号权重
    * @return int - 多单信号权重（0-100，0=无信号，值越大信号越强烈）
    * @note 核心判断逻辑（基于 FrAMA 自适应特性）：
    *       1. 形态0（价格位置）：收盘价在 FrAMA 上方 → 返回形态0权重（确认多头趋势基础）；
    *       2. 形态1（反向交叉）：收盘价在 FrAMA 下方，但开盘价在上方（价格下穿后反弹），且 FrAMA 向上 → 返回形态1权重（潜在反转，优先级最高）；
    *       3. 形态2（同向交叉）：收盘价在 FrAMA 上方，FrAMA 向上，且开盘价在下方（价格上穿后延续） → 返回形态2权重（趋势延续确认）；
    *       4. 形态3（穿刺形态）：收盘价在 FrAMA 上方，FrAMA 向上，开盘价在上方，但最低价短暂下穿 FrAMA 后回归 → 返回形态3权重（回调结束）；
    *       5. 信号优先级：形态1 > 形态0 > 形态2 > 形态3（满足高优先级则覆盖低优先级）
    */
   virtual int       LongCondition(void);

   /**
    * @brief 判断当前市场是否满足空单（卖出）开仓条件，返回信号权重
    * @return int - 空单信号权重（0-100，0=无信号，值越大信号越强烈）
    * @note 核心判断逻辑（与多单相反，基于 FrAMA 自适应特性）：
    *       1. 形态0（价格位置）：收盘价在 FrAMA 下方 → 返回形态0权重（确认空头趋势基础）；
    *       2. 形态1（反向交叉）：收盘价在 FrAMA 上方，但开盘价在下方（价格上穿后回落），且 FrAMA 向下 → 返回形态1权重（潜在反转，优先级最高）；
    *       3. 形态2（同向交叉）：收盘价在 FrAMA 下方，FrAMA 向下，且开盘价在上方（价格下穿后延续） → 返回形态2权重（趋势延续确认）；
    *       4. 形态3（穿刺形态）：收盘价在 FrAMA 下方，FrAMA 向下，开盘价在下方，但最高价短暂上穿 FrAMA 后回归 → 返回形态3权重（反弹结束）；
    *       5. 信号优先级：形态1 > 形态0 > 形态2 > 形态3（满足高优先级则覆盖低优先级）
    */
   virtual int       ShortCondition(void);

protected:
   //----------------------------------------------------------------
   // 内部辅助方法：FrAMA 指标初始化（仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 创建并初始化 FrAMA 指标（绑定品种、周期、参数，注册到指标集合）
    * @param indicators [in] 指标集合对象（用于管理 FrAMA 指标）
    * @return bool - 初始化结果：true=成功（指标创建+参数配置完成），false=失败
    * @note 内部流程：
    *       1. 检查指标集合指针有效性；
    *       2. 将 FrAMA 指标对象（m_ma）添加到指标集合；
    *       3. 调用 m_ma.Create() 绑定当前交易品种、周期及指标参数（周期、偏移、应用价格）；
    *       4. 若添加或创建失败，输出错误日志并返回 false
    */
   bool              InitMA(CIndicators *indicators);

   //----------------------------------------------------------------
   // 数据读取与差值计算：快捷获取指标与价格关系（保护，子类可直接调用）
   //----------------------------------------------------------------
   /**
    * @brief 获取指定索引的 FrAMA 指标值
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - FrAMA 指标值（反映经分形自适应平滑后的平均价格）
    */
   double            MA(int ind);

   /**
    * @brief 计算指定索引K线的 FrAMA 指标差值（当前K线 - 前一根K线，反映指标趋势方向）
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - FrAMA 差值（>0=指标向上，<0=指标向下，反映趋势方向）
    */
   double            DiffMA(int ind);

   /**
    * @brief 计算指定索引K线的开盘价与 FrAMA 的差值（反映开盘时价格与指标的位置关系）
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 差值（>0=开盘价在FrAMA上方，<0=开盘价在FrAMA下方）
    */
   double            DiffOpenMA(int ind);

   /**
    * @brief 计算指定索引K线的最高价与 FrAMA 的差值（反映日内高点与指标的位置关系）
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 差值（>0=最高价在FrAMA上方，<0=最高价在FrAMA下方）
    */
   double            DiffHighMA(int ind);

   /**
    * @brief 计算指定索引K线的最低价与 FrAMA 的差值（反映日内低点与指标的位置关系）
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 差值（>0=最低价在FrAMA上方，<0=最低价在FrAMA下方）
    */
   double            DiffLowMA(int ind);

   /**
    * @brief 计算指定索引K线的收盘价与 FrAMA 的差值（反映收盘时价格与指标的位置关系）
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 差值（>0=收盘价在FrAMA上方，<0=收盘价在FrAMA下方，核心趋势判断依据）
    */
   double            DiffCloseMA(int ind);
  };
//+------------------------------------------------------------------+